package com.terrynoya.Resource
{
    import com.terrynoya.Resource.events.ExternalClassLoaderEvent;
    import com.terrynoya.Resource.events.ExternalLibraryEvent;
    import com.terrynoya.Resource.events.ExternalResManagerEvent;
    import com.terrynoya.Resource.lib.ExternalLibrary;
    import com.terrynoya.Resource.lib.LibraryStatus;
    import com.terrynoya.Resource.lib.Linkage;
    import com.terrynoya.Resource.lib.LinkageFoundHandler;
    import com.terrynoya.utils.UzHashMap;

    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.net.URLLoader;
    import flash.net.URLRequest;

    use namespace uz_resourceInternal;

    [Event(name="inited", type="com.ultizen.terrynoya.events.UzResourceManagerEvent")]

    [Event(name="library_loaded", type="com.ultizen.terrynoya.events.UzResourceManagerEvent")]

    [Event(name="library_error", type="com.ultizen.terrynoya.events.UzResourceManagerEvent")]

    /**
     * 资源加载管理器
     * @author yaojianzhou
     */
    public class ExternalResManagerImpl extends EventDispatcher
    {
        private var _xmlData:XML;

        private var _libs:Array; //UzLibrary

        /**
         * 加载队列
         */
        private var _loadStack:UzHashMap; //UzLibrary,UzExternalClassLoader

        /**
         *
         */
        public function ExternalResManagerImpl()
        {
            this._loadStack = new UzHashMap();
        }

        /**
         *
         * @param classLoader
         */
        public function loadClass(classLoader:ExternalClassLoader):void
        {
            var flh:LinkageFoundHandler;

            for (var i:int = 0; i < this._libs.length; i++)
            {
                var lib:ExternalLibrary = this._libs[i];
                var tmpflh:LinkageFoundHandler = lib.findLinkage(classLoader.name);
                if (tmpflh.index != -1)
                {
                    flh = tmpflh;
                    break;
                }
            }


            if (flh == null)
            {
                evt = new ExternalClassLoaderEvent(ExternalClassLoaderEvent.CLASS_NOT_FOUND);
                classLoader.dispatchEvent(evt);
                return;
            }

            var rltlib:ExternalLibrary = flh.lib;
            var evt:ExternalClassLoaderEvent;
            var arr:Array;
            
            if (rltlib.status == LibraryStatus.READY)
            {
                rltlib.addEventListener(ExternalLibraryEvent.LOAD_COMPLETE, libraryLoadedHandler);
                rltlib.addEventListener(ExternalLibraryEvent.IO_ERROR, libraryIOErrorHandler);
                rltlib.loadResource();

                this._loadStack.add(rltlib, []);
                arr = this._loadStack.getValue(rltlib);
                arr.push(classLoader);
            }
            else if (rltlib.status == LibraryStatus.LOADING)
            {
                arr = this._loadStack.getValue(rltlib);
                arr.push(classLoader);
                trace("loading..");
            }
            else if (rltlib.status == LibraryStatus.COMPLETE)
            {
                evt = new ExternalClassLoaderEvent(ExternalClassLoaderEvent.COMPLETE);
                classLoader.dispatchEvent(evt);
            }
            else if (rltlib.status == LibraryStatus.IO_ERROR)
            {
                evt = new ExternalClassLoaderEvent(ExternalClassLoaderEvent.IO_ERROR);
                this.dispatchEvent(evt);
            }
        }

        /**
         * 初始化配置文件
         * @param urlpath
         * 
         */
        public function loadConfig(urlpath:String):void
        {
            var urlLoader:URLLoader = new URLLoader();
            urlLoader.addEventListener(Event.COMPLETE, onXMLLoaded);
            urlLoader.load(new URLRequest(urlpath));
        }
		
        private function onXMLLoaded(e:Event):void
        {
            this._libs = [];

            this._xmlData = new XML(e.currentTarget.data);
            for (var i:int = 0; i < this._xmlData.library.length(); i++)
            {
                var libXML:XML = this._xmlData.library[i];
                var lib:ExternalLibrary = this.getLibByXML(libXML);
                this._libs.push(lib);
            }

            var evt:ExternalResManagerEvent = new ExternalResManagerEvent(ExternalResManagerEvent.INITED);
            this.dispatchEvent(evt);
        }
		
		/**
         *	对配置文件进行解析
         */
        private function getLibByXML(xml:XML):ExternalLibrary
        {
            var path:String = xml.@path;
            var lib:ExternalLibrary = new ExternalLibrary(path);
            for (var i:int = 0; i < xml.script.length(); i++)
            {
                var linkageId:String = xml.script[i].def[0].@id;
                var linkageName:String = xml.script[i].@name;
                var linkage:Linkage = new Linkage(linkageName, linkageId);
                lib.addLinkage(linkage);
            }
            return lib;
        }

        /**
         * 外部库加载错误 事件
         * 当外部库加载出现错误，则所有向这个库请求的ExternalLoader队列清空，抛出IOERROR事件
         * @private
         */
        private function libraryIOErrorHandler(e:ExternalLibraryEvent):void
        {
            var arr:Array = this._loadStack.getValue(e.currentTarget);
            this.popAllLoaders(ExternalLibrary(e.currentTarget), ExternalClassLoaderEvent.IO_ERROR);
        }

        private function libraryLoadedHandler(e:ExternalLibraryEvent):void
        {
            var arr:Array = this._loadStack.getValue(e.currentTarget);
            this.popAllLoaders(ExternalLibrary(e.currentTarget), ExternalClassLoaderEvent.COMPLETE);
        }

        /**
         * 监听到外部库发生某事件时，需要弹出所有等候队列时使用的模板方法
         * @param lib
         * @param libEventName
         */
        private function popAllLoaders(lib:ExternalLibrary, libEventName:String):void
        {
            var arr:Array = this._loadStack.getValue(lib);
            while (arr.length > 0)
            {
                var ld:ExternalClassLoader = arr.pop();
                var evt:ExternalClassLoaderEvent = new ExternalClassLoaderEvent(libEventName);
                ld.dispatchEvent(evt);
            }
        }

        /**
         *	调试跟踪
         */
        public function printStack():void
        {
            this._loadStack.eachValue(printArr);
            trace(this._loadStack.length);
        	trace("-------------------------");
        }

        /**
         *
         * @param obj
         */
        public function printArr(obj:*):void
        {
            trace(obj);
        }

    }
}